DEFINITION MODULE  ConvertStr;

(*****************************************************************************)
(* Dieses Modul enthaelt Prozeduren zur Wandlung der Standarddatentypen in   *)
(* und aus Strings. Neben den auf einen Datentyp festgelegten gibt es noch   *)
(* Universalprozeduren, die fuer die Umwandlung beliebiger Datentypen der    *)
(* entsprechenden Laenge gedacht sind; Hier kann auch die Zahlenbasis angege-*)
(* ben werden, sodass zum Beispiel auch BITSETs ausgegeben werden koennen    *)
(* ( mit "NumToStr", "StrToNum" und basis = "bin", allerdings ohne fuehrende *)
(* Nullen ).                                                                 *)
(*                                                                           *)
(* Jede Prozedur gibt im Parameter <done> zurueck, ob die Umwandlung ohne    *)
(* Fehler verlaufen ist; moegliche Fehler sind:                              *)
(*                                                                           *)
(*  - Bei der Umwandlung in Strings:                                         *)
(*                Der String ist zu kurz                                     *)
(*                                                                           *)
(*  - Bei der Umwandlung aus Strings:                                        *)
(*                Der String enthaelt ein ungueltiges Zeichen,               *)
(*                Wertebereich des Typs wuerde ueberschritten                *)
(*                nicht genuegend Stellen angegeben ( bei "StrToBitset" )    *)
(*                                                                           *)
(* Falls erforderlich, kann die 'genaue' Fehlerursache danach mit            *)
(* "LastResult" ermittelt werden. Es kann auch eine automatische Fehlermel-  *)
(* dung erfolgen, falls mit "AssignConvHandler" eine entsprechende Prozedur  *)
(* definiert wurde.                                                          *)
(*                                                                           *)
(* Bei der Wandlung aus Strings werden fuehrende Leerzeichen ignoriert;      *)
(* fuehrende Nullen sind erlaubt. Die Wertangabe darf nur aus Zeichen beste- *)
(* hen, die fuer den jeweiligen Typ erlaubt sind, und hinter dem letzten     *)
(* gueltigen Zeichen muss entweder der String beendet sein, oder es muss ein *)
(* Begrenzungszeichen ( <= 7FH, nicht alphanumerisch ) folgen.               *)
(* Steht hinter dem letzten gueltigen Zeichen trotzdem noch etwas, so ist    *)
(* zwar <done> = FALSE, aber in <wert> wird der bis zu diesem ersten un-     *)
(* gueltigen Zeichen konvertierte Wert zurueckgeliefert. Sonst wird im Falle *)
(* von done = FALSE in <wert> Null zurueckgeliefert.                         *)
(*                                                                           *)
(* Bei der Wandlung in Strings wird  das Ergebnis rechtsbuendig mit der      *)
(* angegebenen Feldweite geschrieben; passt das Ergebnis nicht in die angege-*)
(* bene Feldbreite, werden soviele Zeichen belegt wie fuer die Darstellung   *)
(* noetig sind.                                                              *)
(* Ist <feld> gleich Null oder eins, ist der Ergebnisstring so kurz wie      *)
(* moeglich - es gibt keine fuehrenden Leerzeichen.                          *)
(*___________________________________________________________________________*)
(*  12-Feb-90 , Holger Kleinschmidt                                          *)
(*****************************************************************************)

FROM  SYSTEM  IMPORT  (* TYPE *)  BYTE, WORD;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)

  TYPE  Base = ( bin,        (* '0'..'1'                   *)
                 oct,        (* '0'..'7'                   *)
                 dec,        (* '0'..'9'                   *)
                 hex );      (* '0'..'9','a'..'f','A'..'F' *)

        ConvertResult = ( converted, strToShort, invalidDigit, overflow );

        ConvHandler   = PROCEDURE ((* EIN/ -- procname *) ARRAY OF CHAR,
                                   (* EIN/ -- convres  *) ConvertResult  );

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)

  PROCEDURE  AssignConvHandler ((* EIN/ -- *) handler : ConvHandler );

  PROCEDURE  UnAssignConvHandler;

 (*-------------------------------------------------------------------------
  | Ist mit "AssignConvHandler" eine Fehlerbehandlungsroutine definiert wor-|
  | den, so wird diese jedesmal automatisch aufgerufen, wenn bei einer Kon- |
  | vertierung ein Fehler aufgetreten ist; die Prozedur erhaelt als Parame- |
  | ter den Fehler vom Typ "ConvertResult" und den Namen der Prozedur, in   |
  | der der Fehler auftrat.                                                 |
  | Nach Programmstart oder Aufruf von "UnAssignConvHandler" wird vom Modul |
  | kein Handler beim Auftritt eines Fehlers aktiviert.                     |
  |                                                                         |
  | Die automatische Fehlermeldung ist besonders in der Testphase zu emp-   |
  | fehlen, eine einfache Routine koennte z.B. so aussehen:                 |
  |                                                                         |
  |   PROCEDURE Convhandler( proc : ARRAY OF CHAR; fehler : ConvertResult );|
  |     BEGIN                                                               |
  |       WriteLn;                                                          |
  |       WriteString('Fehler bei Zahlkonvertierung - ');                   |
  |       WriteString('Prozedur '); WriteString(proc); Write(':');          |
  |       WriteLn;                                                          |
  |       CASE  fehler  OF                                                  |
  |          converted : WriteString('Alles ok');                           |
  |        | strToShort :                                                   |
  |            WriteString('Die Zahldarstellung passt nicht in den String');|
  |        | invalidDigit :                                                 |
  |            WriteString('In dem String ist ein fuer den zu wandelnden'); |
  |            WriteLn;                                                     |
  |            WriteString('Wert ungueltiges Zeichen aufgetreten');         |
  |        | overflow:                                                      |
  |            WriteString('Der Wertebereich des zu wandelnden Typs wurde');|
  |            WriteString(' ueberschritten');                              |
  |        ELSE                                                             |
  |            WriteString('Totaler Zusammenbruch...');                     |
  |       END; (* CASE *)                                                   |
  |       WriteLn;                                                          |
  |       IF  ( NextIndex() > HIGH( str ))  OR                              |
  |           ( str[NextIndex()] = 0C    )                                  |
  |       THEN                                                              |
  |         WriteString('Stringende aufgetreten');                          |
  |       ELSE                                                              |
  |         WriteString('Das fehlerhafte Zeichen ist: ');                   |
  |         Write("'"); Write(str[NextIndex()]); Write("'");                |
  |         WriteString('  Index: '); WriteCard(NextIndex(),0);             |
  |       END;                                                              |
  |       WriteLn; WriteLn;                                                 |
  |     END  Convhandler;                                                   |
   -------------------------------------------------------------------------*)



  PROCEDURE  LastConvResult ( ): ConvertResult;

 (*-------------------------------------------------------------------------
  | Liefert das Resultat der letzten Konvertierung, falls <done> nicht aus- |
  | reichen sollte. Moegliche Kombinationen sind:                           |
  |                                                                         |
  |   - converted   : letzte Operation war ok., <done> war = TRUE           |
  |   - strToShort  : moegliches Resultat aller Prozeduren, die Werte in    |
  |                   Strings wandeln: Der Laenge des Strings reicht nicht  |
  |                   fuer die Darstellung des Wertes.                      |
  |   - invalidDigit: moegliches Resultat aller Prozeduren, die Strings in  |
  |                   Werte wandeln: im String ist ein Zeichen aufgetreten, |
  |                   das keine gueltige Ziffer fuer den zu wandelnden Typ  |
  |                   darstellt, oder der String enthaelt ueberhaupt keine  |
  |                   druckbaren Zeichen; bei "StrToBitset" auch, wenn      |
  |                   weniger oder mehr als 16 Bits angegeben sind.         |
  |   - overflow    : moegliches Resultat aller Prozeduren, die Strings in  |
  |                   Werte wandeln, ausser "StrToBool" und "StrToBitset":  |
  |                   Die im String angegebene Zahlendarstellung ist zu     |
  |                   gross fuer den zu wandelnden Typ.                     |
   -------------------------------------------------------------------------*)


  PROCEDURE  NextIndex ( ): INTEGER;

 (*-------------------------------------------------------------------------
  | Hiermit kann nach einer Konvertierung der Index des Zeichens im String  |
  | ernittelt werden, das hinter dem letzten fuer die Konvertierung benutz- |
  | ten steht. Trat bei der Konvertierung ein Fehler auf, so ist das der    |
  | Index des fehlerhaften Zeichens.                                        |
   -------------------------------------------------------------------------*)

(*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*)


  PROCEDURE  BoolToStr ((* EIN/ -- *)     wert : BOOLEAN;
                        (* EIN/ -- *)     feld : CARDINAL;
                        (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                        (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToBool ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                        (* -- /AUS *) VAR wert : BOOLEAN;
                        (* -- /AUS *) VAR done : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Aus- und Eingabe boolscher Werte. "BoolToStr" liefert je nach <wert>    |
  | in <str> den <feld> Zeichen breiten rechtsbuendigen Text 'TRUE' oder    |
  | 'FALSE'.                                                                |
  | "StrToBool" akzeptiert als Eingaben: 'TRUE' und 'T' fuer <wert> = TRUE  |
  | bzw. 'FALSE' und 'F' fuer <wert> = FALSE.                               |
  | Es sind auch Kleinbuchstaben erlaubt.                                   |
   -------------------------------------------------------------------------*)


  PROCEDURE  BitsetToStr ((* EIN/ -- *)     menge: BITSET;
                          (* EIN/ -- *)     feld : CARDINAL;
                          (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                          (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToBitset ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                          (* -- /AUS *) VAR menge: BITSET;
                          (* -- /AUS *) VAR done : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Konvertierung von BITSETs. Im Gegensatz zur Konvertierung mit "NumToStr"|
  | werden immer 16 Stellen ausgegeben und verlangt, also auch fuehrende    |
  | Nullen; '0' steht fuer ein nicht vorhandenes Element,'1' steht fuer ein |
  | vorhandenes. Die Numerierung der Bits ist von rechts nach links, also   |
  | so, wie sie auf Maschinenebene ist.                                     |
   -------------------------------------------------------------------------*)


  PROCEDURE  CardToStr     ((* EIN/ -- *)     wert : CARDINAL;
                            (* EIN/ -- *)     feld : CARDINAL;
                            (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  LongCardToStr ((* EIN/ -- *)     wert : LONGCARD;
                            (* EIN/ -- *)     feld : CARDINAL;
                            (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR done : BOOLEAN       );


  PROCEDURE  StrToCard     ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR wert : CARDINAL;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToLongCard ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR wert : LONGCARD;
                            (* -- /AUS *) VAR done : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Kardinalzahlen werden dezimal interpretiert, deshalb sind nur die       |
  | Ziffern von '0' bis '9' gueltige Zeichen; direkt vor der Zahl darf ein  |
  | '+' stehen, hinter der Zahl darf kein 'H','B' oder 'C' als Zahlenbasis- |
  | angabe stehen. Bei der Ausgabe wird kein Vorzeichen geschrieben.        |
  |                                                                         |
  |            ['+']digit{digit}(IsDelimiter|Stringende)                    |
   -------------------------------------------------------------------------*)



  PROCEDURE  IntToStr     ((* EIN/ -- *)     wert : INTEGER;
                           (* EIN/ -- *)     feld : CARDINAL;
                           (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                           (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  LongIntToStr ((* EIN/ -- *)     wert : LONGINT;
                           (* EIN/ -- *)     feld : CARDINAL;
                           (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                           (* -- /AUS *) VAR done : BOOLEAN       );


  PROCEDURE  StrToInt     ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                           (* -- /AUS *) VAR wert : INTEGER;
                           (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToLongInt ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                           (* -- /AUS *) VAR wert : LONGINT;
                           (* -- /AUS *) VAR done : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Bei "StrToInt" und "StrToLongInt" darf das erste Nicht-Leerzeichen ein  |
  | '-' oder '+' sein, hinter dem unmittelbar Ziffern zwischen '0' und '9'  |
  | folgen.                                                                 |
  | Bei "IntToStr" und "LongIntToStr" wird fuer das Vorzeichen immer ein    |
  | zusaetzliches Zeichen benoetigt; wenn <wert> positiv ist, steht vor der |
  | Zahl ein Leerzeichen.                                                   |
  |                                                                         |
  |            ['+'|'-']digit{digit}(IsDelimiter|Stringende)                |
   -------------------------------------------------------------------------*)


  PROCEDURE  ShortNumToStr ((* EIN/ -- *)     wert : BYTE;
                            (* EIN/ -- *)     basis: Base;
                            (* EIN/ -- *)     feld : CARDINAL;
                            (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  NumToStr      ((* EIN/ -- *)     wert : WORD;
                            (* EIN/ -- *)     basis: Base;
                            (* EIN/ -- *)     feld : CARDINAL;
                            (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  LongNumToStr  ((* EIN/ -- *)     wert : LONGCARD;
                            (* EIN/ -- *)     basis: Base;
                            (* EIN/ -- *)     feld : CARDINAL;
                            (* -- /AUS *) VAR str  : ARRAY OF CHAR;
                            (* -- /AUS *) VAR done : BOOLEAN       );


  PROCEDURE  StrToShortNum ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                            (* EIN/ -- *)     basis: Base;
                            (* -- /AUS *) VAR wert : BYTE;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToNum      ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                            (* EIN/ -- *)     basis: Base;
                            (* -- /AUS *) VAR wert : WORD;
                            (* -- /AUS *) VAR done : BOOLEAN       );

  PROCEDURE  StrToLongNum  ((* EIN/ -- *)     str  : ARRAY OF CHAR;
                            (* EIN/ -- *)     basis: Base;
                            (* -- /AUS *) VAR wert : LONGCARD;
                            (* -- /AUS *) VAR done : BOOLEAN       );

 (*-------------------------------------------------------------------------
  | Die Prozeduren wandeln einen beliebigen Wert der angegebenen Laenge in  |
  | einen String bzw. umgekehrt; die gewuenschte Zahlenbasis kann angegeben |
  | werden.                                                                 |
  | <wert> wird immer ohne Vorzeichen betrachtet.                           |
  | Bei "StrToNum", "StrToLongNum" und "StrToShortNum" darf die Zahlenbasis |
  | nicht als letztes Zeichen hinter dem Wert stehen, dies gibt entweder    |
  | einen Fehler, oder wenn die Zahlenbasis "hex" = 16 ist, werden die An-  |
  | gaben 'C' und 'B' als zur Zahl gehoerig betrachtet, da sie gueltige Zif-|
  | fern zu dieser Zahlenbasis darstellen!                                  |
  |                                                                         |
  |            ['+']digit{digit}(IsDelimiter|Stringende)                    |
  |                                                                         |
  | 'digit' entsprechend der Zahlenbasis.                                   |
   -------------------------------------------------------------------------*)

END  ConvertStr.
